#include "preHeader.h"
#include "RPCHelper.h"
#include "Session/GameServerMgr.h"

std::unordered_map<uint32, std::string_view> RPCHelper::ReadReplyDataDict(INetStream& pck)
{
	std::unordered_map<uint32, std::string_view> datas;
	datas.reserve(pck.Read<uint16>());
	while (!pck.IsReadableEmpty()) {
		uint32 key;
		std::string_view data;
		pck >> key >> data;
		datas.emplace(key, data);
	}
	return datas;
}

const std::string_view& RPCHelper::TryGetReplyData(
	const std::unordered_map<uint32, std::string_view>& datas, uint32 key)
{
	auto itr = datas.find(key);
	return itr != datas.end() ? itr->second : emptyStringView;
}

GErrorCode RPCHelper::RPCPullPlayerInfo(Coroutine::YieldContext& ctx,
	uint32 playerId, uint32 flags, std::string_view& rst,
	AsyncTaskOwner *owner, time_t timeout)
{
	NetPacket rpcReqPck(SGX_PULL_CHARACTER_INFOS);
	rpcReqPck << (u32)PullValueFlag::NonDict << flags << playerId;
	auto errCode = sGameServerMgr.
		RPCInvoke2GS(rpcReqPck, ctx.GetRPCInvokeCb(), owner, timeout);
	if (errCode != RPCErrorNone) {
		return CommonInternalError;
	}
	auto resp = ctx.WaitRPCInvokeResp();
	if (resp.err != RPCErrorNone) {
		return CommonInternalError;
	}
	if (resp.pck->IsReadableEmpty()) {
		return CommonInternalError;
	}
	rst = resp.pck->CastReadableStringView();
	return CommonSuccess;
}

GErrorCode RPCHelper::RPCPullPlayerInfos(Coroutine::YieldContext& ctx,
	const uint32 playerIds[], size_t playerNum, uint32 flags,
	std::unordered_map<uint32, std::string_view>& rst,
	AsyncTaskOwner *owner, time_t timeout)
{
	NetPacket rpcReqPck(SGX_PULL_CHARACTER_INFOS);
	rpcReqPck << (u32)0 << flags;
	for (size_t i = 0; i < playerNum; ++i) {
		rpcReqPck << playerIds[i];
	}
	auto errCode = sGameServerMgr.
		RPCInvoke2GS(rpcReqPck, ctx.GetRPCInvokeCb(), owner, timeout);
	if (errCode != RPCErrorNone) {
		return CommonInternalError;
	}
	auto resp = ctx.WaitRPCInvokeResp();
	if (resp.err != RPCErrorNone) {
		return CommonInternalError;
	}
	rst = RPCHelper::ReadReplyDataDict(*resp.pck);
	for (size_t i = 0; i < playerNum; ++i) {
		if (RPCHelper::TryGetReplyData(rst, playerIds[i]).empty()) {
			return CommonInternalError;
		}
	}
	return CommonSuccess;
}

void RPCHelper::PackRPCPlayerInfos(INetPacket& pck,
	const uint32 playerIds[], size_t playerNum,
	const std::unordered_map<uint32, std::string_view>& rst)
{
	for (size_t i = 0; i < playerNum; ++i) {
		auto dataStr = RPCHelper::TryGetReplyData(rst, playerIds[i]);
		if (!dataStr.empty()) {
			pck.Append(dataStr.data(), dataStr.size());
		} else {
			assert(false && "can't reach here.");
		}
	}
}
